import { InteractionEvents, KeyEventNames, InteractionHandler } from './InteractionHandler';
import { BasePlayer } from '../player/BasePlayer';
import { ControlMessage } from '../controlMessage/ControlMessage';
import { TouchControlMessage } from '../controlMessage/TouchControlMessage';
import MotionEvent from '../MotionEvent';
import ScreenInfo from '../ScreenInfo';
import { ScrollControlMessage } from '../controlMessage/ScrollControlMessage';
import { BroadcastService } from './BroadcastService';
import { StreamClientScrcpy } from '../googDevice/client/StreamClientScrcpy';
import { CommandControlMessage } from '../controlMessage/CommandControlMessage';
import DeviceMessage from '../googDevice/DeviceMessage';
import Point from '../Point';
import Position from '../Position';
const TAG = '[FeaturedTouchHandler]';

export interface InteractionHandlerListener {
	sendMessage : (message : ControlMessage) => void;
}
// 1. 定义一个接口描述我们需要的消息结构
interface AdaptedControlMessage {
	action : number;
	position ?: Position;
	pressure ?: number;
	buttons ?: number;
	pointerId ?: number
}
export class FeaturedInteractionHandler extends InteractionHandler {
	public readonly listener : StreamClientScrcpy;
	public readonly player : BasePlayer;

	private static readonly touchEventsNames : InteractionEvents[] = [
		'touchstart', 'touchend', 'touchmove', 'touchcancel',
		'mousedown', 'mouseup', 'mousemove', 'wheel'
	];
	private static readonly keyEventsNames : KeyEventNames[] = ['keydown', 'keyup'];
	public static SCROLL_EVENT_THROTTLING_TIME = 30;
	private readonly storedFromMouseEvent = new Map<number, TouchControlMessage>();
	private readonly storedFromTouchEvent = new Map<number, TouchControlMessage>();
	private lastScrollEvent ?: { time : number; hScroll : number; vScroll : number };
	private ALLOWED_SCROLL_SELECTORS = ['.video', '#video-container'];
	constructor(player : BasePlayer, listener : StreamClientScrcpy) {
		super(player, FeaturedInteractionHandler.touchEventsNames, FeaturedInteractionHandler.keyEventsNames);
		this.player = player;
		this.listener = listener;
		BroadcastService.getInstance().registerClient(listener);
		this.tag.addEventListener('mouseleave', this.onMouseLeave);
		this.tag.addEventListener('mouseenter', this.onMouseEnter);
	}
	// 新增：判断滚轮事件是否来自级联选择器（放行该区域的滚动）
	private isCascaderArea(target : HTMLElement | null) : boolean {
		if (!target) return false;
		// 匹配级联选择器相关的元素（根据你的 Vue 组件样式调整选择器）
		const cascaderSelectors = [
			'.custom-cascader-popper', // 级联面板的 popper 类（之前你加的 popper-class）
			'.el-cascader',            // Element Plus 级联选择器的默认类
			'.el-cascader__dropdown',  // 级联下拉面板的默认类
			'.el-popover[placement="right"]' // 更换机型的 popover（可选，精准匹配）
		];
		// 检查目标元素或其祖先是否匹配上述选择器
		return cascaderSelectors.some(selector => {
			return target.matches(selector) || target.closest(selector) !== null;
		});
	}
	// 恢复之前的滚轮事件处理方法
	public buildScrollEvent(event : WheelEvent, screenInfo : ScreenInfo, player : BasePlayer) : ControlMessage[] {
		// 👇 新增：如果是级联区域的滚动，直接返回空消息（不处理）
		const isCascaderScroll = this.isCascaderArea(event.target as HTMLElement);
		if (isCascaderScroll) {
			return [];
		}

		// 原有逻辑：判断是否在云手机允许的滚动区域
		const isInAllowedArea = this.checkIfEventInAllowedArea(event.target as HTMLElement);
		if (!isInAllowedArea) {
			return [];
		}
		const messages : ControlMessage[] = [];
		const touchOnClient = InteractionHandler.buildTouchOnClient(event, screenInfo, this.player);
		if (touchOnClient) {
			const hScroll = event.deltaX > 0 ? -1 : event.deltaX < 0 ? 1 : 0;
			const vScroll = event.deltaY > 0 ? -1 : event.deltaY < 0 ? 1 : 0;
			const time = Date.now();

			if (
				!this.lastScrollEvent ||
				time - this.lastScrollEvent.time > FeaturedInteractionHandler.SCROLL_EVENT_THROTTLING_TIME ||
				this.lastScrollEvent.vScroll !== vScroll ||
				this.lastScrollEvent.hScroll !== hScroll
			) {
				this.lastScrollEvent = { time, hScroll, vScroll };
				messages.push(new ScrollControlMessage(touchOnClient.touch.position, hScroll, vScroll));
			}
		}
		return messages;
	}
	// 新增：校验事件源是否在允许的元素范围内
	private checkIfEventInAllowedArea(target : HTMLElement | null) : boolean {
		if (!target) return false;

		// 检查目标元素本身或其祖先是否匹配允许的选择器
		return this.ALLOWED_SCROLL_SELECTORS.some(selector => {
			// 检查目标元素是否匹配选择器
			if (target.matches(selector)) return true;
			// 检查目标元素的祖先是否匹配选择器
			return target.closest(selector) !== null;
		});
	}
	// 修改 onInteraction 方法中的消息发送逻辑
	protected onInteraction(event : MouseEvent | TouchEvent | WheelEvent) : void {
		const allCloudPhones : StreamClientScrcpy[] = BroadcastService.getInstance().getAllClients();
		let messages : ControlMessage[] = [];
		// 处理事件
		if (event instanceof WheelEvent) {
			const isCascaderScroll = this.isCascaderArea(event.target as HTMLElement);
			if (isCascaderScroll) {
				// 级联选择器的滚动：不处理云手机逻辑，也不阻止事件（让级联正常滚动）
				return;
			}
			const screenInfo = this.player.getScreenInfo();
			if (screenInfo) {
				messages = this.buildScrollEvent(event, screenInfo, this.player);
			}
		} else if ((event instanceof MouseEvent) || event instanceof TouchEvent) {
			messages = this.generateOriginalMessages(event);
		}
		// 发送消息到所有设备
		allCloudPhones.forEach((cloudPhone, deviceIndex) => {
			if (!cloudPhone || !cloudPhone.sendMessage) return;
			const targetScreenInfo = cloudPhone.player?.getScreenInfo();
			const sourceScreenInfo = this.player.getScreenInfo();
			if (!targetScreenInfo || !sourceScreenInfo) return;
			messages.forEach((message) => {
				try {
					let messageToSend = message;
					// 如果是触摸消息，需要适配坐标
					if (message instanceof TouchControlMessage) {
						messageToSend = this.adaptMessageToDevice(
							message,
							targetScreenInfo,
							sourceScreenInfo
						);
					}
					// 如果是滚动消息，也需要适配坐标！
					else if (message instanceof ScrollControlMessage) {
						messageToSend = this.adaptScrollMessageToDevice(
							message,
							targetScreenInfo,
							sourceScreenInfo
						);
					}
					cloudPhone.sendMessage(messageToSend);
				} catch (error) {
					console.error(`设备${deviceIndex}消息发送失败`, error);
				}
			});
		});
		// 👇 关键：只有非级联区域的事件，才阻止传播（避免影响级联）
		if (event.cancelable && !(event instanceof WheelEvent && this.isCascaderArea(event.target as HTMLElement))) {
			event.preventDefault();
		}
		if (!(event instanceof WheelEvent && this.isCascaderArea(event.target as HTMLElement))) {
			event.stopPropagation();
		}
	}

	// 新增：滚动消息坐标适配方法
	private adaptScrollMessageToDevice(
		originalMsg : ScrollControlMessage,
		targetScreenInfo : ScreenInfo,
		sourceScreenInfo : ScreenInfo
	) : ScrollControlMessage {
		// 1. 获取源坐标和屏幕尺寸
		const originalPoint = originalMsg.position.point;
		const sourceSize = sourceScreenInfo.videoSize;
		const targetSize = targetScreenInfo.videoSize;

		// 安全检查
		if (sourceSize.width === 0 || sourceSize.height === 0 ||
			targetSize.width === 0 || targetSize.height === 0) {
			console.error('无效的屏幕尺寸，使用原始滚动坐标');
			return originalMsg;
		}

		// 2. 计算坐标比例
		const ratioX = originalPoint.x / sourceSize.width;
		const ratioY = originalPoint.y / sourceSize.height;

		// 3. 计算目标坐标
		let targetX = Math.round(ratioX * targetSize.width);
		let targetY = Math.round(ratioY * targetSize.height);

		// 4. 边界检查
		targetX = Math.max(0, Math.min(targetSize.width - 1, targetX));
		targetY = Math.max(0, Math.min(targetSize.height - 1, targetY));

		// 5. 处理横竖屏旋转差异
		const isSourceLandscape = sourceSize.width > sourceSize.height;
		const isTargetLandscape = targetSize.width > targetSize.height;

		let adaptedHScroll = originalMsg.hScroll;
		let adaptedVScroll = originalMsg.vScroll;

		if (isSourceLandscape !== isTargetLandscape) {
			// 旋转场景：交换X/Y坐标和滚动方向
			[targetX, targetY] = [targetY, targetX];
			[adaptedHScroll, adaptedVScroll] = [adaptedVScroll, adaptedHScroll];
		}

		// 6. 创建适配后的滚动消息
		return new ScrollControlMessage(
			new Position(
				new Point(targetX, targetY),
				targetSize
			),
			adaptedHScroll,
			adaptedVScroll
		);
	}
	// 新增：触摸消息坐标适配方法
	private adaptMessageToDevice(
		originalMsg : TouchControlMessage,
		targetScreenInfo : ScreenInfo,
		sourceScreenInfo : ScreenInfo
	) : TouchControlMessage {
		// 1. 获取源坐标和屏幕尺寸
		const originalPoint = originalMsg.position.point;
		const sourceSize = sourceScreenInfo.videoSize;
		const targetSize = targetScreenInfo.videoSize;

		// 安全检查
		if (sourceSize.width === 0 || sourceSize.height === 0 ||
			targetSize.width === 0 || targetSize.height === 0) {
			console.error('无效的屏幕尺寸，使用原始坐标');
			return originalMsg;
		}

		// 2. 计算坐标比例
		const ratioX = originalPoint.x / sourceSize.width;
		const ratioY = originalPoint.y / sourceSize.height;

		// 3. 计算目标坐标
		let targetX = Math.round(ratioX * targetSize.width);
		let targetY = Math.round(ratioY * targetSize.height);

		// 4. 边界检查
		targetX = Math.max(0, Math.min(targetSize.width - 1, targetX));
		targetY = Math.max(0, Math.min(targetSize.height - 1, targetY));

		// 5. 处理横竖屏旋转差异
		const isSourceLandscape = sourceSize.width > sourceSize.height;
		const isTargetLandscape = targetSize.width > targetSize.height;

		if (isSourceLandscape !== isTargetLandscape) {
			// 旋转场景：交换X/Y坐标
			[targetX, targetY] = [targetY, targetX];
		}

		// 6. 创建适配后的触摸消息
		return new TouchControlMessage(
			originalMsg.action,
			originalMsg.pointerId,
			new Position(
				new Point(targetX, targetY),
				targetSize
			),
			originalMsg.pressure,
			originalMsg.buttons
		);
	}
	// 原始消息生成逻辑
	private generateOriginalMessages(event : MouseEvent | TouchEvent) : ControlMessage[] {
		let messages : ControlMessage[] = [];
		let storage : Map<number, TouchControlMessage>;

		if (!this.player) {
			console.error('当前实例没有player属性');
			return messages;
		}

		const currentScreenInfo = this.player.getScreenInfo();
		if (!currentScreenInfo) {
			return messages;
		}

		if (event instanceof MouseEvent) {
			if (event.target !== this.tag) return messages;

			if (window['WheelEvent'] && event instanceof WheelEvent) {
				// 滚轮事件：走滚动逻辑，不处理点击
				messages = this.buildScrollEvent(event, currentScreenInfo, this.player);
			} else {
				// 非滚轮鼠标事件：处理点击（mousedown/mouseup）和移动（mousemove）
				storage = this.storedFromMouseEvent;
				messages = this.buildTouchEvent(
					event,
					currentScreenInfo,
					storage,
					this.player
				) as unknown as ControlMessage[];
			}
		} else if (window['TouchEvent'] && event instanceof TouchEvent) {
			if (event.target !== this.tag) return messages;
			storage = this.storedFromTouchEvent;
			messages = this.formatTouchEvent(
				event,
				currentScreenInfo,
				storage,
				this.player
			) as unknown as ControlMessage[];
		}
		return messages;
	}
	protected onKey(event : KeyboardEvent) : void {
		if (!this.lastPosition) {
			return;
		}
		const screenInfo = this.player.getScreenInfo();
		if (!screenInfo) {
			return;
		}
		const { ctrlKey, shiftKey } = event;
		const { target, button, buttons, clientY, clientX } = this.lastPosition;
		const type = InteractionHandler.SIMULATE_MULTI_TOUCH;
		const props = { ctrlKey, shiftKey, type, target, button, buttons, clientX, clientY };
		this.buildTouchEvent(props, screenInfo, new Map(), this.player);
	}

	private onMouseEnter = () : void => {
		this.over = true;
	};
	private onMouseLeave = () : void => {
		this.lastPosition = undefined;
		this.over = false;
		this.storedFromMouseEvent.forEach((message) => {
			this.listener.sendMessage(InteractionHandler.createEmulatedMessage(MotionEvent.ACTION_UP, message));
		});
		this.storedFromMouseEvent.clear();
		this.clearCanvas();
	};

	public release() : void {
		super.release();
		this.tag.removeEventListener('mouseleave', this.onMouseLeave);
		this.tag.removeEventListener('mouseenter', this.onMouseEnter);
		this.storedFromMouseEvent.clear();
	}
}